<?php

/**
 * QPHP
 *
 * Copyright (c) 2022 QPHP
 *
 * @author lbnnbs
 * @copyright Copyright (c) 2022 lbnnbs QPHP (https://gitee.com/lbnnbs/qphp)
 * @license AGPLv3 License
 *
 * Token鉴权类
 */
class TokenAuth {
    
    static private $_auth_config;
    static private $_auth_prefix = 'auth_';
    
    /**
     * 写入鉴权相关数据
     */
    static private function _set($token, $uid, $scope) {
        self::$_auth_config || self::$_auth_config = Sys::getCfg('auth');
        $expire = self::$_auth_config['expire'];
        $value = MEncode($uid);
        if (self::$_auth_config['single']) {
            self::_clear_tokens($uid, $scope); // 单用户登录，清理之前其他客户端登录的token
        }
        cache(self::$_auth_config['prefix'] . self::$_auth_prefix . $scope, $token, $value, $expire);
        self::_store_tokens($uid, $token, $scope);
    }
    
    /**
     * 存储该用户所有客户端登录的token
     */
    static private function _store_tokens($uid, $token, $scope) {
        self::$_auth_config || self::$_auth_config = Sys::getCfg('auth');
        $expire = self::$_auth_config['expire'];
        $key = md5($uid);
        $tokens = cache(self::$_auth_config['prefix'] . self::$_auth_prefix . $scope, $key);
        if (!$tokens || !is_array($tokens)) {
            $tokens = [$token];
        } else {
            if (!in_array($token, $tokens) === false) {
                $tokens[] = $token;
            } else {
                return;
            }
        }
        cache(self::$_auth_config['prefix'] . self::$_auth_prefix . $scope, $key, $tokens, $expire);
    }
    
    /**
     * 清理该用户所有客户端登录的token，一般用于修改密码后退出所有登录的客户端
     */
    static private function _clear_tokens($uid, $scope) {
        self::$_auth_config || self::$_auth_config = Sys::getCfg('auth');
        $key = md5($uid);
        // 读取该用户所有客户端登录的token
        $tokens = cache(self::$_auth_config['prefix'] . self::$_auth_prefix . $scope, $key);
        if ($tokens) {
            if (is_array($tokens)) {
                foreach ($tokens as $token) {
                    self::_remove($token, $scope);
                }
            }
            cache(self::$_auth_config['prefix'] . self::$_auth_prefix . $scope, $key, null, 0, true);
        }
    }
    
    /**
     * 读取鉴权相关数据
     */
    static private function _get($token, $scope) {
        self::$_auth_config || self::$_auth_config = Sys::getCfg('auth');
        if ($value = cache(self::$_auth_config['prefix'] . self::$_auth_prefix . $scope, $token)) {
            return MDecode($value);
        }
        return false;
    }
    
    /**
     * 移除鉴权相关数据
     * @param string $token 鉴权token
     * @param string $scope 鉴权范围
     */
    static private function _remove($token, $scope) {
        self::$_auth_config || self::$_auth_config = Sys::getCfg('auth');
        cache(self::$_auth_config['prefix'] . self::$_auth_prefix . $scope, $token, null, 0, true);
    }
    
    /**
     * 登入用户，返回token
     * @param integer $uid 用户ID
     * @param string $scope 鉴权范围
     * @return string token
     */
    static public function Login($uid, $scope = 'user') {
        $token = randString(32);
        self::_set($token, $uid, $scope);
        return $token;
    }
    
    /**
     * 登出用户
     * @param string $token 鉴权token
     * @param string $scope 鉴权范围
     */
    static public function Logout($token, $scope = 'user') {
        self::_remove($token, $scope);
    }
    
    /**
     * 清理指定用户的所有token，一般用于修改密码后退出所有登录的客户端
     * @param integer $uid 用户ID
     * @param string $scope 鉴权范围
     */
    static public function Clear($uid, $scope = 'user') {
        self::_clear_tokens($uid, $scope);
    }
    
    /**
     * 检查是否登录，并返回用户ID
     * @param string $token 鉴权token
     * @param string $scope 鉴权范围
     */
    static public function GetAuthedUid($token, $scope = 'user') {
        return self::_get($token, $scope);
    }
    
    /**
     * 刷新Token
     * @param string $token 鉴权token
     * @param string $scope 鉴权范围
     * @return string 新的token
     */
    static public function Refresh($token, $scope = 'user') {
        if ($uid = self::GetAuthedUid($token, $scope)) {
            self::Logout($token, $scope);
            return self::Login($uid, $scope);
        }
        return false;
    }
    
}